[Note] Node.js: module


Posted by urlun0404 on 2022-12-05

在處理前端的時候很常會用到npm這個node套件管理系統,因此使用套件時不免俗地也會很常需要用到Node.js的關鍵字或內建模組。

模組(module)是JavaScript ES2015(ES6)以後才出現的語法,白話來說所謂的模組就是將一個或好幾個寫好的JavaScript程式碼分離出來、包裝成可重複引用(import)的檔案。一個模組可能有多個變數和函式,但是這些變數和函式必須輸出(export),才能被其他檔案所利用。

現階段除了JavaScript ES6原生的模組系統,也有其他兩個常見的模組系統,分別是Node.js的CommonJS系統和AMD(asynchronous module definition)系統,而這篇主要是講述Node.js的模組系統。


Module Systems

雖然前面有說到Node.js常見的模組系統是CommonJS,但現今Node.jS其實已經有兩種系統並存,分別是CommonJS和ECMAScript:

  • CommonJS:是Node.js一開始設計的模組系統,也是待會要深入討論的模組系統。
  • ECMAScript modules @Node.js v18.12.1:則是Node.js後來支援、遵循ECMAScript標準的模組系統,語法跟原生的JavaScript ES2015沒兩樣。

一般來說,Node.js的模組系統依來源可大致分為以下三種類型的模組,分別是Node.js的內建模組(built-in modules)、自製模組(self-made modules)和別人所製作並且交由NPM(node package manager)管理的第三方模組

  1. Built-in modules
  2. Self-made modules
  3. Third-party modules: modules are made from other people and managed by NPM

等會會以CommonJS模組系統為主介紹如何使用內建或第三方模組,以及如何自製模組。



CommonJS: Module Wrapper

在使用Node.js執行模組以前,Node.js會自動將每一個要執行的JavaScript檔案內程式碼放進一個函式中,我們稱這個函式為「module wrapper」:

(function(exports, require, module, __filename, __dirname) {
    // Module code actually lives in here
});

Module wrapper是Node.js會自動加入的函式,不用自己手動加在程式碼外面。

將程式碼用module wrapper封裝起來有兩個好處:

  • 可以將原來全域範疇的程式碼(top-level code)封裝成函式範疇的程式碼;
  • Module wrapper的module和exports會提供好用的屬性或物件,像是__firename__dirnameexports



CommonJS: Module

這一小篇會跟前面module wrapper的 exportsrequire

1. Self-made Modules

假設寫了一個包含兩個函式的檔案morning.js,如果想將這個檔案輸出成一個模組,可以利用前面提到的 exports 物件,以下會示範兩種輸出、引入的方式。

(1) 以物件形式輸出

第一種是以"物件"形式輸出:

// morning.js

function morning(name){
    return `Good morning ${name}!`
}

function mogern(name){
    return `Guten mogern ${name}!`
}

module.exports.morning = morning;
exports.mogern = mogern;

exportsmodule.exports 的縮寫寫法,以上兩種寫法都可以將函式放入一個名為 exports 的物件。

如果有用 console.log(exports) 去檢查 exports 這個物件會看到:

exports = {
    morning: [Function morning],
    mogern: [Function mogern]
}


假設現在想在另一份檔案引入模組,可用關鍵字 require 引入檔案:

const morning = require('./morning');

console.log(morning.morning('Jimmy'));   // Good morning Jimmy!
console.log(morning.mogern('Ivy'));   // Guten mogern Ivy!


(2) 以函式形式輸出

第二種則是直接輸出整個函式,以常用的伺服器建立模組express為例:

// express
function express () {
    // ...
}

module.exports = express;

引入的時候可以直接呼叫這個函式:

// app.js
const express = require('express');
const app = express();   // 呼叫函式

// ...



2. Node.js Built-in Modules

引入Node.js內建模組的方式就與前面引入自製模組的方式相同,以下引入幾個常用的內建模組作為示範:

// path
const path = require('path');
console.log(path.join(__dirname, 'index.html'));   // d://fake/index.html

// url
const url = require('url');
const parsedUrl = url.parse('...');

// fs
const fs = require('fs');
fs.watchFile('msg.txt', (curr, prev)=>{
    console.log(curr);
});

因為ECMAScript module大約是Node.js v12後出來的,目前最新文件的範例已經改用ECMAScript module引入模組的方式示範,如果需要看 require 模組的範例可以查看Node.js v11版本的文件


3. Third-party modules download from NPM

最後一個是第三方模組的引入,引入方式基本上和前面兩者差不多。唯一差別在於首先得到npm網站下載第三方套件,以下載目前前端最常見的React套件為例:
npm install react

因為在下載Node.js的時候就會跟著一起下載 npm 這個模組管理工具,所以如果是windows的電腦,可以先在命令提示字元(cmd)將路徑移至要下載套件的專案底下,然後

  1. 初始化專案的模組管理檔案 package.jsonnpm init
  2. 安裝React套件:npm i react


References
JavaScript modules
ES6 Modules: A Beginner’s Guide
The Complete JavaScript Course 2023: From Zero to Expert!
2022網頁開發全攻略(HTML, CSS, JavaScript, React, SQL, Node, more)
Modules: CommonJS modules @Node.js v18.x
Modules: ECMAScript modules @Node.js v18.x
The module wrapper @Node.js v18.x


#Backend #node.js







Related Posts

CH5 IF, else 條件判斷入門

CH5 IF, else 條件判斷入門

Fake Vapes and How to Avoid Them

Fake Vapes and How to Avoid Them

JS30 Day 13 筆記

JS30 Day 13 筆記


Comments